// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once

#include <pollux/vector/flat_vector.h>

namespace kumo::pollux {
    /// StringVectorBuffer is a utility for managing a buffer that can grow
    /// dynamically as needed. It is designed to work with a FlatVector of
    /// StringView objects, allowing writing to the flat_vector with zero copying.
    ///
    /// The buffer starts with an initial capacity and can grow
    /// up to a specified maximum capacity. Once existing capacity is full,
    /// The buffer increases its capacity by kGrowFactor each time,
    /// up to the maximum capacity.
    ///
    /// Note: when the resizes happens, old buffer will stay in
    /// `FlatVector::stringBuffers_`, the partial last row is duplicated in
    /// both old buffer and new buffer.
    class StringVectorBuffer {
    public:
        StringVectorBuffer(
            FlatVector<StringView> *vector,
            size_t initialCapacity,
            size_t maxCapacity);

        /// Appends a byte to the buffer.
        /// TODO: supports appending multiple bytes at a time.
        void appendByte(int8_t value);

        /// Sets the row at 'rowId' with current buffered data without data copy.
        void flushRow(vector_size_t rowId);

    private:
        MELON_ALWAYS_INLINE size_t writableCapacity() const {
            POLLUX_CHECK_GE(currentCapacity_, currentPosition_);
            return currentCapacity_ - currentPosition_;
        }

        MELON_ALWAYS_INLINE size_t unflushedRowSize() const {
            POLLUX_CHECK_GE(currentPosition_, startPosition_);
            return currentPosition_ - startPosition_;
        }

        /// Try to increase the capacity of the buffer by at least growSize.
        /// If the max capacity is reached,
        /// the buffer can't be resized and POLLUX_CHECK will fail.
        void ensureCapacity(size_t growSize);

        char *data() const {
            return rawBuffer_;
        }

        // The factor to multiple the current capacity by when resizing.
        static constexpr size_t kGrowFactor = 2;

        // The maximum capacity of the buffer we can grow to.
        const size_t maxCapacity_;

        FlatVector<StringView> *const vector_;
        char *rawBuffer_ = nullptr;

        // Keeps track of where the current row starts in the rawBuffer.
        size_t startPosition_ = 0;
        // Keeps track of the current write position in the rawBuffer.
        size_t currentPosition_ = 0;
        // The size of the buffer that accepts the new append.
        size_t currentCapacity_ = 0;
        // The total size of the buffers have been allocated.
        size_t totalCapacity_ = 0;
    };
} // namespace kumo::pollux
